package com.huawei.admins.platform.gateway.core.component.predicate;

import org.reactivestreams.Publisher;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;

import java.util.function.Function;
import java.util.function.Predicate;

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {

    default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
        return new AndAsyncPredicate<>(this, other);
    }

    default AsyncPredicate<T> negate() {
        return new NegateAsyncPredicate<>(this);
    }

    default AsyncPredicate<T> not(AsyncPredicate<? super T> other) {
        return new NegateAsyncPredicate<>(other);
    }

    default AsyncPredicate<T> or(AsyncPredicate<? super T> other) {
        return new OrAsyncPredicate<>(this, other);
    }

    static AsyncPredicate<ServerWebExchange> from(Predicate<? super ServerWebExchange> predicate) {
        return new DefaultAsyncPredicate<>(AsyncPredicate.wrapIfNeeded(predicate));
    }

    static Predicate<ServerWebExchange> wrapIfNeeded(Predicate<? super ServerWebExchange> other) {
        Predicate<ServerWebExchange> right;

        if (other instanceof GatewayPredicateWrapper) {
            right = (GatewayPredicateWrapper) other;
        } else {
            right = new GatewayPredicateWrapper(other);
        }
        return right;
    }

    class GatewayPredicateWrapper implements Predicate<ServerWebExchange> {

        private final Predicate<? super ServerWebExchange> delegate;

        public GatewayPredicateWrapper(Predicate<? super ServerWebExchange> delegate) {
            Assert.notNull(delegate, "delegate GatewayPredicate must not be null");
            this.delegate = delegate;
        }

        public boolean test(ServerWebExchange exchange) {
            return this.delegate.test(exchange);
        }

        @Override
        public String toString() {
            return this.delegate.getClass().getSimpleName();
        }

    }

}
